package com.iteaj.util.xml;

import com.iteaj.util.core.UtilsException;
import com.iteaj.util.core.UtilsType;
import org.springframework.util.Assert;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * jdk：1.8
 *
 * @author lcz
 * create time：2019/5/16
 */
public class Jaxb2Adapter implements XmlAdapter {
    private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap(64);

    @Override
    public String toXml(Object obj) {
        return Optional.ofNullable(obj)
            .map(item->{
                StringWriter writer = new StringWriter();
                try {
                    Marshaller marshaller = createMarshaller(item.getClass());
                    marshaller.marshal(obj, writer);
                } catch (JAXBException e) {
                    throw new UtilsException(e, UtilsType.XML);
                }
                return writer.toString();
            }).orElse(null);
    }

    @Override
    public <T> T toBean(String xml, Class<T> clazz) {
        return Optional.ofNullable(xml).map(item-> {
            try {
                return (T) createUnmarshaller(clazz).unmarshal(new StringReader(xml));
            } catch (JAXBException e) {
                throw new UtilsException(e, UtilsType.XML);
            }
        }).orElse(null);
    }

    protected final Marshaller createMarshaller(Class clazz) {
        try {
            JAXBContext jaxbContext = this.getJaxbContext(clazz);
            return jaxbContext.createMarshaller();
        } catch (JAXBException var3) {
            throw new UtilsException(var3, UtilsType.XML);
        }
    }

    protected final Unmarshaller createUnmarshaller(Class clazz) throws JAXBException {
        try {
            JAXBContext jaxbContext = this.getJaxbContext(clazz);
            return jaxbContext.createUnmarshaller();
        } catch (JAXBException var3) {
            throw new UtilsException(var3, UtilsType.XML);
        }
    }

    protected final JAXBContext getJaxbContext(Class clazz) {
        Assert.notNull(clazz, "'clazz' must not be null");
        JAXBContext jaxbContext = this.jaxbContexts.get(clazz);
        if (jaxbContext == null) {
            try {
                jaxbContext = JAXBContext.newInstance(clazz);
                this.jaxbContexts.putIfAbsent(clazz, jaxbContext);
            } catch (JAXBException var3) {
                throw new UtilsException(var3, UtilsType.XML);
            }
        }

        return jaxbContext;
    }
}
